package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.content.model.qo.QueryCourseModel;
import com.xuecheng.api.system.model.dto.CourseCategoryDTO;
import com.xuecheng.common.constant.CoursePubTemplateKey;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.agent.SystemApiAgent;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.controller.CourseAuditController;
import com.xuecheng.content.convert.CourseBaseConvert;
import com.xuecheng.content.convert.CoursePubConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.CourseMarket;
import com.xuecheng.content.entity.CoursePub;
import com.xuecheng.content.entity.CourseTeacher;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.content.service.CourseMarketService;
import com.xuecheng.content.service.CoursePubService;
import com.xuecheng.content.service.TeachplanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 课程基本信息 服务实现类
 *
 * @author dongliang
 */
@Slf4j
@Service
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseService {

    @Autowired
    private CourseMarketService courseMarketService;
    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 带条件分页查询
     *
     * @param params 封装分页数据
     * @param model  前端传入课程基础信息 Qo
     * @return PageVO 分页结果封装
     */
    public PageVO<CourseBaseDTO> queryCourseList(PageRequestParams params, QueryCourseModel model, Long companyId) {

        //1判断分页数据 每页条数 大于0
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        //2构建查询条件对象LambdaQueryWrapper
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();
        //相当于SELECT COUNT(*) FROM course_base WHERE (name LIKE '%SpringBoot%' AND audit_status = '202004' AND company_id = '1232141425')
        //课程名不为null时模糊查询
        queryWrapper.like(StringUtil.isNotBlank(model.getCourseName()),
                CourseBase::getName, model.getCourseName());
        //状态不为null时,条件查询
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()),
                CourseBase::getAuditStatus, model.getAuditStatus());
        queryWrapper.eq(!ObjectUtils.nullSafeEquals(companyId, CourseAuditController.OPERATION_FLAG), CourseBase::getCompanyId, companyId);

        //3构建mp分页对象
        Page<CourseBase> page = new Page<>(params.getPageNo(), params.getPageSize());

        //4.根据分页查询数据
        Page<CourseBase> pageResult = this.page(page, queryWrapper);

        //5拿到分页好的records数据存放到List<CourseBase>
        List<CourseBase> records = pageResult.getRecords();
        //拿到总条数
        long total = pageResult.getTotal();

        //6.将List<CourseBase>转换成List<CourseBaseDTO>
        List<CourseBaseDTO> baseDTOList = Collections.emptyList();
        if (!CollectionUtils.isEmpty(records)) {
            baseDTOList = CourseBaseConvert.INSTANCE.entitys2dtos(records);
        }

        //7返回结果封装PageVo数据
        PageVO pageVO = new PageVO(baseDTOList, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }

    /**
     * 新增课程基本信息
     *
     * @param dto 前端传来的数据用于封装给po与数据库交互
     * @return courseBaseDTO 新增课程基本信息结果
     */
    @Transactional //1.是否开启事务 新增操作需要开启事务
    public CourseBaseDTO createCourseBase(CourseBaseDTO dto) {
        //2.判断关键数据
        criticalData(dto);

        //3.将dto转为po数据
        CourseBase courseBase = CourseBaseConvert.INSTANCE.dto2entity(dto);
        //并且赋值审核状态的默认值 * 保存：未提交  添加的数据默认是未提交的状态
        courseBase.setAuditStatus(CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode());

        //4.保存数据
        //4.1 保存课程基础信息,并判断保存结果
        boolean baseResult = this.save(courseBase);
        if (!baseResult) {
            throw new RuntimeException("保存课程基础信息失败");
        }

        //4.2 保存课程营销信息,并判断保存结果
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setCourseId(courseBase.getId());
        courseMarket.setCharge(dto.getCharge());
        //判断收费状态
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(dto.getCharge())) {
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费模式价格不能为空");
            }
            courseMarket.setPrice(dto.getPrice().floatValue());
        }
        if (CourseChargeEnum.CHARGE_NO.getCode().equals(dto.getCharge())) {
            int price = 0;
            if (!dto.getPrice().equals(new BigDecimal(price))) {
                throw new RuntimeException("免费模式下价格应为0");
            }
        }

        boolean courseMarketResult = courseMarketService.save(courseMarket);
        if (!courseMarketResult) {
            throw new RuntimeException("保存课程营销信息失败");
        }


        Long baseId = courseBase.getId();
        //5.如果操作成功，将查询的最新数据转为dto并返回
        return getLastCourseBaseDTO(dto, baseId);
    }

    /**
     * 根据课程Id查询此需更新课程信息
     *
     * @param courseBaseId 课程ID
     * @return courseBaseDTO  根据Id查询此课程基本信息结果
     */
    public CourseBaseDTO getCourseBase(Long courseBaseId, Long companyId) {
        //1.判断关键数据 courseBaseId  companyId
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id为空");
        }
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("未获取令牌,companyId为空");
        }

        //2.根据id查询此需更新的课程
        CourseBaseDTO courseBaseDTO = getCourseBaseDTO(courseBaseId, companyId);

        return courseBaseDTO;
    }

    /**
     * 更新录播课程基本信息
     *
     * @param dto 更新的封装的数据接收前端数据
     * @return 更新后课程基本信息结果
     */
    @Transactional //1.开启事务
    public CourseBaseDTO modifyCourseBase(CourseBaseDTO dto) {

        //2.判断关键数据
        criticalData(dto);
        //修改时：课程id是必须存在
        Long courseBaseId = dto.getCourseBaseId();
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id不存在");
        }

        //3.判断业务数据
        //课程基础信息表
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, dto.getCompanyId());
        //判断审批状态未提交.审批未通过才可修改
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120011);
        }

        //课程营销数据表 判断charge模式和 price
        CourseMarket courseMarket = getCourseMarket(courseBaseId);

        //4.dto转成po准备课程基础表修改,但courseBaseId、companyid、auditstatus、status不容修改
        CourseBase po = CourseBaseConvert.INSTANCE.dto2entity(dto);
        po.setCompanyId(null);
        po.setAuditStatus(null);
        po.setStatus(null);

        boolean baseResult = this.updateById(po);

        //5.判断修改结果
        if (!baseResult) {
            throw new RuntimeException("修改课程基础表失败");
        }
        //6.课程营销表修改
        LambdaUpdateWrapper<CourseMarket> courseMarketWrapper = new LambdaUpdateWrapper<>();
        String charge = dto.getCharge();
        courseMarketWrapper.set(CourseMarket::getCharge, charge);
        //如果是收费
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(charge)) {
            if (ObjectUtils.isEmpty(dto.getPrice())) {
                throw new RuntimeException("收费模式价格不能为空");
            }
            //价格不为空
            courseMarketWrapper.set(CourseMarket::getPrice, dto.getPrice().floatValue());
        }
        courseMarketWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        //修改
        boolean courseMarketResult = courseMarketService.update(courseMarketWrapper);

        //7.判断营销表修改结果
        if (!courseMarketResult) {
            throw new RuntimeException("营销表内容修改失败");
        }
        //8.查询数据并转为dto返回
        Long baseId = courseBase.getId();
        CourseBaseDTO courseBaseDTO = getLastCourseBaseDTO(dto, baseId);

        return courseBaseDTO;

    }

    /**
     * 删除录播课程基本信息
     *
     * @param courseBaseId 课程id
     * @param companyId    令牌公司id
     */
    @Transactional //1.开启事务
    public boolean removeCourseBaseById(Long courseBaseId, Long companyId) {
        //2.判断关键数据 courseBaseId  companyId
        if (ObjectUtils.isEmpty(courseBaseId)) {
            throw new RuntimeException("课程id为空");
        }
        if (ObjectUtils.isEmpty(companyId)) {
            throw new RuntimeException("未获取令牌,companyId为空");
        }

        //2.判断业务数据
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);
        //判断审批状态未提交.审批未通过才可修改
        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            throw new RuntimeException("课程审批状态未通过不允许删除");
        }
        //3.开始逻辑删除
        LambdaUpdateWrapper<CourseBase> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(CourseBase::getChangeDate, LocalDateTime.now());
        wrapper.set(CourseBase::getStatus, CommonEnum.DELETE_FLAG.getCode());
        wrapper.eq(CourseBase::getId, courseBase.getId());
        boolean flag = this.update(wrapper);

        if (!flag) {
            ExceptionCast.cast(ContentErrorCode.E_120023);
        }
        return flag;
    }


    /**
     * 根据课程Id提交课程信息
     *
     * @param courseBaseId 课程id
     * @param companyId    令牌公司id
     */
    @Transactional //1.开启事务
    public void commitCourseBase(Long courseBaseId, Long companyId) {
        /*
         * 业务分析：
         *   1.判断关键数据
         *   2.判断业务数据
         *       课程基础信息
         *           判断是否存在
         *           判断是否是同一家教学机构
         *           判断是否删除
         *           判断审核状态
         *   3.修改课程审核状态
         *       已提交
         * */
        if (ObjectUtils.isEmpty(courseBaseId) ||
                ObjectUtils.isEmpty(companyId)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }
        //2.判断业务数据
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        String auditStatus = courseBase.getAuditStatus();
        if (CourseAuditEnum.AUDIT_PASTED_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus) ||
                CourseAuditEnum.AUDIT_PUBLISHED_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120018);
        }
        //3.修改课程审核状态 改成已提交
        LambdaUpdateWrapper<CourseBase> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode());
        wrapper.set(CourseBase::getCreateDate, LocalDate.now());
        wrapper.eq(CourseBase::getId, courseBaseId);

        boolean result = this.update(wrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }

    }


    /**
     * 课程信息审核实现-运营
     *
     * @param dto 课程审核时的DTO
     */
    public void approve(CourseBaseDTO dto) {
            /*1.判断关键数据 auditMind  auditStatus  courseid
      2.业务判断
        课程基础信息 存在,删除, 判断审核状态
        审核状态
      3.修改课程审核信息
        auditMind  auditStatus  auditNum（每次+1）*/
        if (ObjectUtils.isEmpty(dto.getAuditMind()) ||
                ObjectUtils.isEmpty(dto.getAuditStatus()) ||
                ObjectUtils.isEmpty(dto.getCourseBaseId())
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120019);
        }

        //2业务判断  判断是否存在 判断是否删除
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getId, dto.getCourseBaseId());
        wrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());
        //查询课程基础表来判断
        CourseBase courseBase = this.getOne(wrapper);

        String auditStatus = courseBase.getAuditStatus();
        if (!CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)
        ) {
            ExceptionCast.cast(ContentErrorCode.E_120021);
        }

        if (ObjectUtils.isEmpty(courseBase)) {
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        Integer status = courseBase.getStatus();
        if (CommonEnum.DELETE_FLAG.getCode().equals(status)) {
            ExceptionCast.cast(ContentErrorCode.E_120020);
        }

        //查询数据库中的次数,存放到redis中
        redisTemplate.opsForValue().set("auditNum", courseBase.getAuditNums());

        //根据key对次数加+1返回的就是每次+1的次数
        Long auditNums = querryAuditNum();
        //更新数据库

        //3.修改课程审核信息 auditMind  auditStatus  auditNum（每次+1）
        LambdaUpdateWrapper<CourseBase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(CourseBase::getAuditMind, dto.getAuditMind());
        updateWrapper.set(CourseBase::getAuditStatus, CourseAuditEnum.AUDIT_PASTED_STATUS.getCode());
        updateWrapper.set(CourseBase::getAuditNums, auditNums);

//        queryAuditNum();
        updateWrapper.set(CourseBase::getCreateDate, LocalDateTime.now());
        updateWrapper.eq(CourseBase::getId, dto.getCourseBaseId());

        boolean result = this.update(updateWrapper);
        if (!result) {
            ExceptionCast.cast(ContentErrorCode.E_120017);
        }
    }

    private Long querryAuditNum() {
        // TODO:redis完成 auditNum（每次+1）需求
        String key = "auditNum";
        Long liveTime = 100L;
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        Long increment = entityIdCounter.getAndIncrement();
        if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始设置过期时间
            entityIdCounter.expire(liveTime, TimeUnit.HOURS);
        }
        return increment;
    }


    /**
     * 判断关键数据 getCompanyId getName getMt getSt getGrade getTeachmode getUsers getCharge
     *
     * @param dto 前端传来的数据用于封装给po与数据库交互
     */
    private void criticalData(CourseBaseDTO dto) {
        //2.判断关键数据 来源 1.数据库约束不能为null的 2.前端表单校验必填项 3.api接口文档
        if (ObjectUtils.isEmpty(dto.getCompanyId())) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        if (StringUtil.isBlank(dto.getName())) {
            throw new RuntimeException("课程名称不能为空");
        }
        if (StringUtil.isBlank(dto.getMt())) {
            throw new RuntimeException("课程大分类不能为空");
        }
        if (StringUtil.isBlank(dto.getSt())) {
            throw new RuntimeException("课程小分类不能为空");
        }
        if (StringUtil.isBlank(dto.getGrade())) {
            throw new RuntimeException("课程等级不能为空");
        }
        if (StringUtil.isBlank(dto.getTeachmode())) {
            throw new RuntimeException("课程教学模式不能为空");
        }
        if (StringUtil.isBlank(dto.getUsers())) {
            throw new RuntimeException("使用人群不能为空");
        }
        if (StringUtil.isBlank(dto.getCharge())) {
            throw new RuntimeException("课程收费不能为空");
        }
    }

    /**
     * 判断业务数据
     *
     * @param courseBaseId 课程id
     * @param companyId    令牌公司id
     * @return 此需更新的课程信息
     */
    private CourseBaseDTO getCourseBaseDTO(Long courseBaseId, Long companyId) {
        //1.课程基础信息  判断是否存在  判断是否是同一家教学机构    判断是否删除
        CourseBase courseBase = getCourseBaseByBaseId(courseBaseId, companyId);

        //2.课程营销信息 判断是否存在
        CourseMarket courseMarket = getCourseMarket(courseBaseId);

        //3.查询数据并转为dto返回
        CourseBaseDTO courseBaseDTO = CourseBaseConvert.INSTANCE.entity2dto(courseBase);

        courseBaseDTO.setCharge(courseMarket.getCharge());
        courseBaseDTO.setPrice(new BigDecimal(courseMarket.getPrice().toString()));

        return courseBaseDTO;
    }

    /**
     * 判断业务数据 1 课程基础信息
     *
     * @param courseBaseId 课程id
     * @param companyId    令牌公司id
     * @return CourseBase 课程基本信息
     */
    private CourseBase getCourseBaseByBaseId(Long courseBaseId, Long companyId) {
        //1.判断是否存在 判断是否是同一家教学机构    判断是否删除
        LambdaQueryWrapper<CourseBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseBase::getId, courseBaseId);
        wrapper.eq(CourseBase::getCompanyId, companyId);
        wrapper.eq(CourseBase::getStatus, CommonEnum.USING_FLAG.getCode());
        //查询课程基础表来判断
        CourseBase courseBase = this.getOne(wrapper);

        if (ObjectUtils.isEmpty(courseBase)) {
            throw new RuntimeException("查询该课程基础信息为空");
        }

        Integer status = courseBase.getStatus();
        if (CommonEnum.DELETE_FLAG.getCode().equals(status)) {
            throw new RuntimeException("该课程已被删除");
        }
        return courseBase;
    }

    /**
     * 判断业务数据 2 课程营销信息
     *
     * @param courseBaseId 课程id
     * @return 课程营销信息
     */
    private CourseMarket getCourseMarket(Long courseBaseId) {
        //1.判断是否存在
        LambdaQueryWrapper<CourseMarket> courseMarketWrapper = new LambdaQueryWrapper<>();
        courseMarketWrapper.eq(CourseMarket::getCourseId, courseBaseId);
        //查询课程基础表来判断
        CourseMarket courseMarket = courseMarketService.getOne(courseMarketWrapper);
        if (ObjectUtils.isEmpty(courseMarket)) {
            throw new RuntimeException("课程营销数据不存在");
        }
        return courseMarket;
    }

    /**
     * 如果操作成功，将查询的最新数据转为dto并返回
     *
     * @param dto 课程基础类
     * @param id  课程id
     * @return DTO 返回的dto
     */
    private CourseBaseDTO getLastCourseBaseDTO(CourseBaseDTO dto, Long id) {
        CourseBase po = this.getById(id);

        CourseBaseDTO resultDTO = CourseBaseConvert.INSTANCE.entity2dto(po);
        resultDTO.setCharge(dto.getCharge());
        resultDTO.setPrice(dto.getPrice());
        return resultDTO;
    }

}
